package org.jflame.web;

import org.jflame.commons.config.ConfigReader;
import org.jflame.commons.file.FileHelper;
import org.jflame.commons.file.MimeTypes;
import org.jflame.commons.util.ArrayHelper;
import org.jflame.commons.util.DataSizeHelper;
import org.jflame.commons.util.DateHelper;
import org.jflame.commons.util.StringHelper;
import org.jflame.context.filemanager.PresignedUrlArgs;

import java.beans.Transient;
import java.util.Arrays;
import java.util.Map;
import java.util.StringJoiner;

import org.apache.commons.lang3.ArrayUtils;

public class WebFileProperties {

    public static final String PREFIX = ConfigReader.JFLAME_CFG_KEY_PREFIX + ".web.file";

    private UploadProp upload = new UploadProp();
    private DownloadProp download = new DownloadProp();

    public UploadProp getUpload() {
        return upload;
    }

    public void setUpload(UploadProp upload) {
        this.upload = upload;
    }

    public DownloadProp getDownload() {
        return download;
    }

    public void setDownload(DownloadProp download) {
        this.download = download;
    }

    /**
     * 文件下载属性
     */
    public static class DownloadProp {

        /**
         * 允许下载的文件类型扩展名
         */
        private String[] allowTypes;
        /**
         * 下载文件的基础目录
         */
        private String dir;
        private boolean keepContentType = false;

        public DownloadProp() {
            this(null);
        }

        public DownloadProp(String[] allowDownloadTypes) {
            // keepContentType = false;
            if (ArrayHelper.isEmpty(allowDownloadTypes)) {
                allowTypes = new String[MimeTypes.DOC_EXTENSIONS.length + MimeTypes.WEB_IMAGE_EXTENSIONS.length];
                allowTypes = ArrayHelper.addAll(allowTypes, MimeTypes.DOC_EXTENSIONS);
                allowTypes = ArrayHelper.addAll(allowTypes, MimeTypes.WEB_IMAGE_EXTENSIONS);

            } else {
                allowTypes = allowDownloadTypes;
            }
        }

        /**
         * 判断是否允许下载的文件类型
         *
         * @param ext 文件扩展名
         * @return
         */
        public boolean isAllowDownload(String ext) {
            if (StringHelper.isEmpty(ext)) {
                return false;
            }
            return ArrayHelper.isEmpty(allowTypes) && ArrayUtils.contains(allowTypes, ext);
        }

        public boolean isPreviewable(String ext) {
            return ext != null && (ArrayHelper.contains(MimeTypes.DOC_EXTENSIONS, ext)
                    || ArrayHelper.contains(MimeTypes.WEB_IMAGE_EXTENSIONS, ext));
        }

        public String[] getAllowTypes() {
            return allowTypes;
        }

        public void setAllowTypes(String[] allowTypes) {
            this.allowTypes = allowTypes;
        }

        public boolean isKeepContentType() {
            return keepContentType;
        }

        public void setKeepContentType(boolean keepContentType) {
            this.keepContentType = keepContentType;
        }

        public String getDir() {
            return dir;
        }

        public void setDir(String dir) {
            this.dir = dir;
        }

        public String downloadFullPath(String fileName) {
            StringHelper.requireNonEmpty(fileName, "fileName must be not empty");
            if (StringHelper.isEmpty(dir)) {
                return fileName;
            }
            return FileHelper.mergePathToUnix(dir, fileName);
        }

        /**
         * 构造一个只允许下载图片[{@link MimeTypes.WEB_IMAGE_EXTENSIONS}]的DownloadProp
         * 
         * @return
         */
        public static DownloadProp ofImage() {
            return new DownloadProp(MimeTypes.WEB_IMAGE_EXTENSIONS);
        }

        /**
         * 构造一个只允许下载常用办公文档格式[{@link MimeTypes.DOC_EXTENSIONS}]的DownloadProp
         * 
         * @return
         */
        public static DownloadProp ofDoc() {
            return new DownloadProp(MimeTypes.DOC_EXTENSIONS);
        }
    }

    /**
     * 文件上传属性
     */
    public static class UploadProp {

        /**
         * 文件上传目录，相对于文件保存的根目录的相对路径
         */
        private String dir = "";

        /**
         * 上传目录是否按日期分开:0不使用,1按年月,2按年/月,3按年月日,4按年/月/日
         */
        private int datePathStyle = 0;

        /**
         * 允许上传的文件类型扩展名
         */
        private String[] allowTypes;

        /**
         * 单个文件最大上传大小(byte)，默认不限制
         */
        private long maxFileSize = -1;

        /**
         * 是否严格检测文件类型,通过文件头检测. 默认只按文件扩展名检测
         */
        private boolean strictlyTypeDetect = false;

        /**
         * 上传预签名url有效期,单位秒
         */
        private int presginExpireTime = 600;
        /**
         * 是否返回上传文件的绝对访问地址,默认返回相对地址
         */
        private boolean returnAbsoluteUrl = false;

        private Map<String,String> fileMeta;

        private transient String uploadFullPath;

        public UploadProp() {
        }

        public UploadProp(String[] allowTypes) {
            this.allowTypes = allowTypes;
        }

        public String getDir() {
            return dir;
        }

        public void setDir(String baseDir) {
            this.dir = baseDir;
        }

        public int getDatePathStyle() {
            return datePathStyle;
        }

        public void setDatePathStyle(int datePathStyle) {
            this.datePathStyle = datePathStyle;
        }

        public String[] getAllowTypes() {
            return allowTypes;
        }

        public void setAllowTypes(String[] allowTypes) {
            this.allowTypes = allowTypes;
        }

        public String[] getAllowUploadTypes() {
            return allowTypes;
        }

        public boolean isStrictlyTypeDetect() {
            return strictlyTypeDetect;
        }

        public void setStrictlyTypeDetect(boolean strictlyTypeDetect) {
            this.strictlyTypeDetect = strictlyTypeDetect;
        }

        public int getPresginExpireTime() {
            return presginExpireTime;
        }

        public void setPresginExpireTime(int presginExpireTime) {
            this.presginExpireTime = presginExpireTime;
        }

        public long getMaxFileSize() {
            return maxFileSize;
        }

        public double maxFileSizeAsKB() {
            return maxFileSize > 0 ? DataSizeHelper.BToKB(maxFileSize) : 0;
        }

        /**
         * 设置单个文件最大限制,单位byte
         *
         * @param maxFileSize
         */
        public void setMaxFileSize(long maxFileSize) {
            this.maxFileSize = maxFileSize;
        }

        public void setMaxFileSize(String maxFileSizeStr) {
            this.maxFileSize = DataSizeHelper.parse(maxFileSizeStr);
        }

        public Map<String,String> getFileMeta() {
            return fileMeta;
        }

        public void setFileMeta(Map<String,String> fileMeta) {
            this.fileMeta = fileMeta;
        }

        public boolean isReturnAbsoluteUrl() {
            return returnAbsoluteUrl;
        }

        public void setReturnAbsoluteUrl(boolean returnAbsoluteUrl) {
            this.returnAbsoluteUrl = returnAbsoluteUrl;
        }

        /**
         * 返回实际上传路径,如果设置了按日期拆分目录再返回基础目录+日期目录,否则等同基础目录
         *
         * @return
         */
        public String getUploadFullPath() {
            if (uploadFullPath == null) {
                uploadFullPath = switch (datePathStyle) {
                    case 1 -> FileHelper.mergePathToUnix(dir, DateHelper.formatNow(DateHelper.yyyyMM));
                    case 2 -> FileHelper.mergePathToUnix(dir, DateHelper.formatNow("yyyy/MM"));
                    case 3 -> FileHelper.mergePathToUnix(dir, DateHelper.formatNow(DateHelper.yyyyMMdd));
                    case 4 -> FileHelper.mergePathToUnix(dir, DateHelper.formatNow(DateHelper.YYYYMMDD_OBLIQUE));
                    default -> dir;
                };
            }
            return uploadFullPath;
        }

        /**
         * 生成上传的完整路径
         *
         * @param fileName 上传文件名
         * @return
         */
        public String uploadFullPath(String fileName) {
            StringHelper.requireNonEmpty(fileName, "fileName must be not empty");
            return FileHelper.mergePathToUnix(getUploadFullPath(), fileName);
        }

        /**
         * 判断是否允许下载的文件类型,如果没有配置{@link #allowTypes}则使用默认限制
         *
         * @param ext 文件扩展名
         * @return
         */
        @Transient
        public boolean isAllowUpload(String ext) {
            if (StringHelper.isEmpty(ext)) {
                return false;
            }
            return ArrayHelper.isNotEmpty(allowTypes) && ArrayUtils.contains(allowTypes, ext);
        }

        /**
         * 判断文件大小是否超过限制
         *
         * @param fileSizeInByte 文件大小(byte)
         * @return 超过限制返回true
         */
        public boolean isSizeExceeds(long fileSizeInByte) {
            return maxFileSize > 0 && fileSizeInByte > maxFileSize;
        }

        public PresignedUrlArgs toPresignedUrlArgs(String fileNameOrExt) {
            return new PresignedUrlArgs(getUploadFullPath(), fileNameOrExt, presginExpireTime, maxFileSize);
        }

        @Override
        public String toString() {
            return new StringJoiner(", ", UploadProp.class.getSimpleName() + "[", "]").add("dir='" + dir + "'")
                    .add("datePathStyle=" + datePathStyle)
                    .add("allowTypes=" + Arrays.toString(allowTypes))
                    .add("maxFileSize=" + maxFileSize)
                    .add("strictlyTypeDetect=" + strictlyTypeDetect)
                    .add("presginExpireTime=" + presginExpireTime)
                    .add("returnAbsoluteUrl=" + returnAbsoluteUrl)
                    .add("fileMeta=" + fileMeta)
                    .add("uploadFullPath='" + uploadFullPath + "'")
                    .toString();
        }
    }
}
